#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <json-c/json.h>      /* json */

#include "config.h"
#include "send_image.h"
#include "gimbal_ctrl.h"

/* 类型定义 */

unsigned int udp_port;

/* 线程 */
pthread_t send_image_tid;
pthread_t gimbal_ctrl_tid;

int main(int argc, char *argv[])
{
    int                ret;
    int                sockfd;
    struct sockaddr_in server_addr;
    struct json_object *send_jobj;
    char               *j2c;
    struct json_object *recv_jobj;
    struct json_object *jvalue1;
    char               *cvalue1;
    struct json_object *jvalue2;
    char               *cvalue2;
    int                ivalue2;
    char               recv_buf[256] = {0};
    
    /* ====== 01.TCP连接阿里云服务器并发送设备信息 ====== */

    /* 流式套接字 */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    /* 判断文件描述符是否创建成功 */
    if (sockfd == -1)
    {
        perror("tcp socket create failed");
        exit(1);
    }

    /* 向 阿里云服务器 发起 TCP 连接 */
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(ALI_PORT);
    server_addr.sin_addr.s_addr = inet_addr(ALI_PNET_ADDR);

    ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

    /* 判断套接字是否连接成功 */
    if (ret == -1)
    {
        perror("socket connect to ali server failed");
        exit(1);
    }

    printf("connect to ali server succeed\n");

    /* 创建 设备信息 json ({"cmd":"info", "deviceid":"0001"}) */
    send_jobj = json_object_new_object();                 /* 创建 json 对象 */
    json_object_object_add(send_jobj, "cmd", 
                           json_object_new_string("info"));     /* key: cmd, value: info */
    json_object_object_add(send_jobj, "deviceid", 
                           json_object_new_string("0001"));     /* key: deviceid, value: 0001 */

    j2c = (char *)json_object_get_string(send_jobj);            /* 将 json 转换为字符串 */

    /* 向 阿里服务器发送 json 设备信息 */
    ret = send(sockfd, j2c, strlen(j2c), 0);

    /* 判断是否发送成功 */
    if (ret == -1)
    {
        perror("send to ali server failed");
        exit(1);
    }

    /* ====== 02.TCP读取阿里云服务器返回的端口信息 ====== */

    /* 读取阿里云服务器读取数据 */
    memset(recv_buf, 0, sizeof(recv_buf));
    ret = recv(sockfd, recv_buf, sizeof(recv_buf), 0);

    /* 从 阿里云服务器接收数据 (json格式) */
    if (ret == -1)
    {
        perror("recv from ali server failed");
        exit(1);
    }

    /* 解析 从阿里云服务器 接收到的 json 数据 ({"cmd":"port_info", "port":"9000"}) */
    recv_jobj = json_tokener_parse(recv_buf);
    jvalue1 = json_object_object_get(recv_jobj, "cmd");     /* 获得 cmd key */
    cvalue1 = (char *)json_object_get_string(jvalue1);       /* 将 json_parse.key1 转换为字符串 */

    /* 判断其值是否是 "port_info" */
    if (strncmp(cvalue1, "port_info", strlen("port_info")) > 0)
    {
        perror("parse recved json failed");
        exit(1);
    }

    jvalue2 = json_object_object_get(recv_jobj, "port");          /* 获得 port key */
    ivalue2 = (int)json_object_get_int(jvalue2);            /* 将 json_parse.key2 转换为整数 */
    udp_port = ivalue2;                                    /* 该值即为 udp 服务器的端口 */
    printf("get udp port form server: %d\n", udp_port);

    /* ====== 03.创建线程去做UDP通讯 ====== */
    /* 创建线程，传入参数 udp_port */
    ret = pthread_create(&send_image_tid, NULL, send_video_to_server, &udp_port);

    /* 判断线程是否创建成功 */
    if (ret != 0)
    {
        perror("send image to server thread create failed");
        exit(1);
    }

    /* ====== 04.创建线程去做云台控制 ====== */
    /* 创建线程 */
    ret = pthread_create(&gimbal_ctrl_tid, NULL, gimbal_control_process, NULL);

    /* 判断线程是否创建成功 */
    if (ret != 0)
    {
        perror("gimbal control thread create failed");
        exit(1);
    }

    /* ====== 05.接收服务器数据并解析处理 ====== */

    while(1)
    {
        /* 读取阿里云服务器读取数据 */
        memset(recv_buf, 0, sizeof(recv_buf));
        ret = recv(sockfd, recv_buf, sizeof(recv_buf), 0);

        /* 从 阿里云服务器接收数据 (json格式) */
        if (ret == -1)
        {
            perror("recv from ali server failed");
            exit(1);
        }

        /*
         * 解析 从阿里云服务器 接收到的 json 数据:
         * {"cmd":"control", "action":"down", "appid":"1000", "deviceid":"0001"}
         */
        recv_jobj = json_tokener_parse(recv_buf);
        jvalue1 = json_object_object_get(recv_jobj, "cmd");  /* 获得 cmd key */
        cvalue1 = (char *)json_object_get_string(jvalue1);        /* 将 jvalue1 转换为字符串 */

        /* 判断其值是否是 "control" */
        if (strncmp(cvalue1, "control", strlen("control")) > 0)
        {
            perror("parse recved json failed");
            exit(1);
        }

        jvalue2 = json_object_object_get(recv_jobj, "action");     /* 获得 action key */
        cvalue2 = (char *)json_object_get_string(jvalue2);         /* 将 jvalue2 转换为 字符串 */

        /* 保护公共数据 */
        pthread_mutex_lock(&gimbal_ctrl.lock);
        memset(gimbal_ctrl.order, 0, sizeof(gimbal_ctrl.order));
        memcpy(gimbal_ctrl.order, cvalue2, strlen(cvalue2));        /* 获得云台转向指令 */
        pthread_mutex_unlock(&gimbal_ctrl.lock);

        /* 告知多级控制线程有控制信号 */
        ctrl_notice_update();
    }
}